#include <iostream>
#include <graphics.h>
#include<vector>
#include<conio.h>
#include<windows.h>
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0) //判断鼠标左键点击的依据
using namespace std;

constexpr auto swidth = 1280;
constexpr auto sheight = 800;

constexpr unsigned int GHP = 5;

constexpr auto hurttime = 1000;

int bullet_speed = 4; // 设置子弹移动的速度
void drawImg(int x, int y, IMAGE* src)
{
	// 变量初始化
	DWORD* pwin = GetImageBuffer();			//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);		//图片缓冲区指针
	int win_w = getwidth();				//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();				//图片宽高
	int src_h = src->getheight();

	// 计算贴图的实际长宽
	int real_w = (x + src_w > win_w) ? win_w - x : src_w;			// 处理超出右边界
	int real_h = (y + src_h > win_h) ? win_h - y : src_h;			// 处理超出下边界
	if (x < 0) { psrc += -x;			real_w -= -x;	x = 0; }	// 处理超出左边界
	if (y < 0) { psrc += (src_w * -y);	real_h -= -y;	y = 0; }	// 处理超出上边界


	// 修正贴图起始位置
	pwin += (win_w * y + x);

	// 实现透明贴图
	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix] >> 24);//计算透明通道的值[0,256) 0为完全透明 255为完全不透明
			if (a > 100)
			{
				pwin[ix] = psrc[ix];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}

void drawImg(int x, int y, int dstW, int dstH, IMAGE* src, int srcX, int srcY)
{
	// 变量初始化
	DWORD* pwin = GetImageBuffer();			//窗口缓冲区指针
	DWORD* psrc = GetImageBuffer(src);		//图片缓冲区指针
	int win_w = getwidth();				//窗口宽高
	int win_h = getheight();
	int src_w = src->getwidth();				//图片宽高
	int src_h = src->getheight();


	// 计算贴图的实际长宽
	int real_w = (x + dstW > win_w) ? win_w - x : dstW;			// 处理超出右边界
	int real_h = (y + dstH > win_h) ? win_h - y : dstH;			// 处理超出下边界
	if (x < 0) { psrc += -x;			real_w -= -x;	x = 0; }	// 处理超出左边界
	if (y < 0) { psrc += (dstW * -y);	real_h -= -y;	y = 0; }	// 处理超出上边界

	//printf("realw,h(%d,%d)\n", real_w, real_h);
	// 修正贴图起始位置
	pwin += (win_w * y + x);

	// 实现透明贴图
	for (int iy = 0; iy < real_h; iy++)
	{
		for (int ix = 0; ix < real_w; ix++)
		{
			byte a = (byte)(psrc[ix + srcX + srcY * src_w] >> 24);//计算透明通道的值[0,256) 0为完全透明 255为完全不透明
			if (a > 100)
			{
				pwin[ix] = psrc[ix + srcX + srcY * src_w];
			}
		}
		//换到下一行
		pwin += win_w;
		psrc += src_w;
	}
}
bool PointInRect(int x, int y, RECT& r)  // 光标点在方框内（未出界）
{
	return(r.left <= x && r.right >= x && r.top <= y && r.bottom >= y);
}

bool recttouchrect(RECT& r1, RECT& r2)   // 玩家是否与敌方子弹接触
{
	RECT r;
	r.left = r1.left - (r2.right - r2.left);
	r.right = r1.right;
	r.top = r1.top - (r2.bottom - r2.top);
	r.bottom = r1.bottom;

	return(r2.left > r.left && r2.left<r.right && r2.top>r.top && r2.top < r.bottom);

}
bool be_playing = true;
class BK
{
public:
	BK(IMAGE& img)
		:img(img)
	{
	}
	void Show()
	{
		drawImg(0, 0, &img);
	}
private:
	IMAGE& img;
};

class Guard      // 玩家本体
{
public:
	Guard(IMAGE& img)
		:img(img), HP(GHP)
	{
		rect.left = swidth / 2 - img.getwidth() / 2;
		rect.top = sheight - img.getheight() / 2;
		rect.right = rect.left + img.getwidth();
		rect.bottom = sheight;
	}
	void Show()
	{
		setfillcolor(RED);
		drawImg(rect.left, rect.top, &img);
		fillrectangle(rect.left, rect.top - 7, rect.left + (img.getwidth() / GHP * HP), rect.top - 2);
	}
	void Control()
	{
		ExMessage mess;
		if (peekmessage(&mess, EM_MOUSE))
		{
			rect.left = mess.x - img.getwidth() / 2;
			rect.top = mess.y - img.getheight() / 2;
			rect.right = rect.right = rect.left + img.getwidth();
			rect.bottom = rect.top + img.getheight();
		}
	}
	bool hurt()
	{
		HP--;
		return (HP == 0) ? false : true;
	}
	bool aid()
	{
		if (HP < GHP)
			HP++;
		return true;
	}
	RECT& GetRect() { return rect; }

private:
	IMAGE& img;
	RECT rect;

	unsigned int HP;
};

int miss;
class Enemy
{
public:
	Enemy(IMAGE& img, int x, IMAGE*& edown)
		:img(img), isdie(false), edownsum(0)
	{
		down[0] = edown[0]; down[1] = edown[0]; down[2] = edown[0];
		down[3] = edown[1]; down[4] = edown[1]; down[5] = edown[1];
		down[6] = edown[3]; down[7] = edown[3]; down[8] = edown[3];
		down[9] = edown[4]; down[10] = edown[4]; down[11] = edown[4];
		down[12] = edown[5]; down[13] = edown[5]; down[14] = edown[5];
		down[15] = edown[6]; down[16] = edown[6]; down[17] = edown[6];
		down[18] = edown[7]; down[19] = edown[7]; down[20] = edown[7];
		down[21] = edown[8]; down[22] = edown[8]; down[23] = edown[8];
		down[24] = edown[9]; down[25] = edown[9]; down[26] = edown[9];
		down[27] = edown[10]; down[28] = edown[10]; down[29] = edown[10];
		down[30] = edown[11]; down[31] = edown[11]; down[32] = edown[11];

		rect.left = x;
		rect.right = rect.left + img.getwidth();
		rect.top = -img.getheight();
		rect.bottom = 0;
	}
	bool Show()
	{

		if (isdie)
		{
			if (edownsum == 36)
			{
				return false;
			}
			drawImg(rect.left, rect.top, down + edownsum);
			edownsum++;

			return true;
		}
		if (rect.top >= sheight)
		{
			miss++;		//癌细胞达到屏幕最低端时，miss值加一，达到十则触发结束判定
			return false;
		}
		rect.top += 2;
		rect.bottom += 2;
		drawImg(rect.left, rect.top, &img);

		return true;
	}

	void Isdie()
	{
		isdie = true;
	}
	RECT& GetRect() { return rect; }

private:
	IMAGE& img;
	RECT rect;
	IMAGE down[36];

	bool isdie;
	int edownsum;
};

class Bullet1    //保卫细胞子弹
{
public:
	Bullet1(IMAGE& img, RECT pr, bool fast)
		:img(img)
	{
		if_fast = fast;
		r.left = pr.left + (pr.right - pr.left) / 2 - img.getwidth() / 2;
		r.right = r.left + img.getwidth();
		r.top = pr.top - img.getwidth();
		r.bottom = r.top + img.getheight();
	}
	bool Show()
	{
		if (r.bottom <= 0)
		{
			return false;
		}
		int velocity = 0;   // 子弹移动速度
		if (if_fast) {
			velocity = 20;
		}
		else {
			velocity = bullet_speed;
		}
		r.top -= velocity;
		r.bottom -= velocity;
		putimage(r.left, r.top, &img);

		return true;
	}
	RECT& GetRect() { return r; }
private:
	IMAGE& img;
	RECT r;
	bool if_fast;
};
class Bullet2
{
public:
	Bullet2(IMAGE& img, RECT pr)
		:img(img)
	{
		r.left = pr.left + (pr.right - pr.left) / 2 - img.getwidth() / 2;
		r.right = r.left + img.getwidth();
		r.top = pr.bottom;
		r.bottom = r.top + img.getheight();
	}
	bool Show()     // 控制子弹速度的函数
	{
		if (r.top >= sheight)
		{
			return false;
		}
		r.top += 3;
		r.bottom += 3;
		putimage(r.left, r.top, &img);

		return true;
	}
	RECT& GetRect() { return r; }
private:
	IMAGE& img;
	RECT r;
};

bool AddEnemy(vector<Enemy*>& es, IMAGE& enemyimg, IMAGE* edown)
{
	Enemy* e = new Enemy(enemyimg, abs(rand()) % (swidth - enemyimg.getwidth()), edown);
	for (auto& i : es)
	{
		if (recttouchrect(i->GetRect(), e->GetRect()))
		{
			delete e;
			return false;
		}
	}
	es.push_back(e);
	return true;
}

bool tip = true;     //用于判断是否显示提示

class Tip
{
public:
	Tip(IMAGE& img, bool& show)
		:img(img)
	{
		if_show = show;
	}
	bool Show()
	{

		if (if_show) {
			drawImg(swidth - img.getwidth(), sheight - img.getheight() * 2 - 40, &img);
		}
		else
			return false;
	}
private:
	IMAGE& img;
	bool if_show;
};
class Tip2
{
public:
	Tip2(IMAGE& img, bool& show)
		:img(img)
	{
		if_show = show;
	}
	bool Show()
	{

		if (if_show) {
			drawImg(swidth - img.getwidth(), sheight - img.getheight() - 20, &img);
		}
		else
			return false;
	}
private:
	IMAGE& img;
	bool if_show;
};
void Welcome()
{
	LPCTSTR tplay = _T("开始游戏");
	LPCTSTR texit = _T("结束游戏");
	RECT tplayr, texitr;
	IMAGE bkimg2;
	setbkcolor(WHITE);
	cleardevice();
	settextcolor(BLACK);

	loadimage(&bkimg2, _T("..\\..\\pic\\bk1.png"));
	BK(bk) = BK(bkimg2);
	bk.Show();

	settextstyle(40, 0, _T("黑体"));

	tplayr.left = swidth / 2 - textwidth(tplay) / 2;
	tplayr.top = sheight / 2;
	tplayr.right = tplayr.left + textwidth(tplay);
	tplayr.bottom = tplayr.top + textheight(tplay);

	texitr.left = swidth / 2 - textwidth(texit) / 2;
	texitr.top = sheight / 3 * 2;
	texitr.right = texitr.left + textwidth(texit);
	texitr.bottom = texitr.top + textheight(texit);

	outtextxy(tplayr.left, tplayr.top, tplay);
	outtextxy(texitr.left, texitr.top, texit);

	EndBatchDraw();
	Sleep(60);

	while (true)        // 进入抉择界面的循环，若选择进入则跳出循环
	{
		ExMessage mess;
		getmessage(&mess, EM_MOUSE);
		if (mess.lbutton)
		{
			if (PointInRect(mess.x, mess.y, tplayr))
			{
				return;
			}
			else if (PointInRect(mess.x, mess.y, texitr))
			{
				exit(0);
			}
		}


	}

	;
}

void Miss(unsigned long long& kill)
{
	TCHAR* str = new TCHAR[128];
	_stprintf_s(str, 128, _T("击杀数：%llu"), kill);

	outtextxy(swidth / 2 - textwidth(str) / 2, sheight / 5, str);
	LPCTSTR comment = _T("");
	if (kill >= 1001 && kill <= 100000)
	{
		comment = _T("Invincible hero（不败的英雄）");
	}
	if (kill >= 701 && kill <= 1000)
	{
		comment = _T("这游戏就是这么玩的，你还真是个人才啊朋友");
	}
	if (kill >= 501 && kill <= 700)
	{
		comment = _T("难道你是天才？");
	}
	if (kill >= 301 && kill <= 500)
	{
		comment = _T("太厉害了8，简直就是神");
	}
	if (kill >= 201 && kill <= 300)
	{
		comment = _T("牛蛙（赞赏）");
	}
	if (kill >= 151 && kill <= 200)
	{
		comment = _T("加油，你马上就要成功了");
	}
	if (kill >= 101 && kill <= 150)
	{
		comment = _T("看来你已经渐入佳境");
	}
	if (kill >= 51 && kill <= 100)
	{
		comment = _T("没关系的，已经很好了");
	}
	if (kill >= 1 && kill <= 50)
	{
		comment = _T("到底是哪里错了");
	}
	if (kill == 0)
	{
		comment = _T("失败并不可耻，至少你还有机会吸取教训");
	}
	LPCTSTR misses = _T("你放跑了太多癌细胞！");
	outtextxy(swidth / 2 - textwidth(comment) / 2, sheight * 2 / 5, comment);
	settextstyle(40, 0, _T("黑体"));
	outtextxy(swidth / 2 - textwidth(misses) / 2, sheight / 2, misses);
	LPCTSTR info = _T(" 按Enter键返回 ");
	settextstyle(20, 0, _T("黑体"));
	outtextxy(swidth / 2 - textwidth(info) / 2, 4 * sheight / 5 - textheight(info), info);

	while (true)
	{
		ExMessage mess;
		getmessage(&mess, EM_KEY);
		if (mess.vkcode == 0x0D)
		{
			return;
		}
	}
}
void Over(unsigned long long& kill)
{
	TCHAR* str = new TCHAR[128];
	_stprintf_s(str, 128, _T("击杀数：%llu"), kill);

	outtextxy(swidth / 2 - textwidth(str) / 2, sheight / 5, str);
	LPCTSTR comment = _T("");
	if (kill >= 1001 && kill <= 100000)
	{
		comment = _T("Invincible hero（不败的英雄）");
	}
	if (kill >= 701 && kill <= 1000)
	{
		comment = _T("这游戏就是这么玩的，你还真是个人才啊朋友");
	}
	if (kill >= 501 && kill <= 700)
	{
		comment = _T("难道你是天才？");
	}
	if (kill >= 301 && kill <= 500)
	{
		comment = _T("太厉害了8，简直就是神");
	}
	if (kill >= 201 && kill <= 300)
	{
		comment = _T("牛蛙（赞赏）");
	}
	if (kill >= 151 && kill <= 200)
	{
		comment = _T("加油，你马上就要成功了");
	}
	if (kill >= 101 && kill <= 150)
	{
		comment = _T("看来你已经渐入佳境");
	}
	if (kill >= 51 && kill <= 100)
	{
		comment = _T("没关系的，已经很好了");
	}
	if (kill >= 1 && kill <= 50)
	{
		comment = _T("到底是哪里错了");
	}
	if (kill == 0)
	{
		comment = _T("失败并不可耻，至少你还有机会吸取教训");
	}
	outtextxy(swidth / 2 - textwidth(comment) / 2, sheight * 2 / 5, comment);
	LPCTSTR death = _T("你的保卫细胞被杀死了！");
	settextstyle(40, 0, _T("黑体"));
	outtextxy(swidth / 2 - textwidth(death) / 2, sheight / 2, death);
	LPCTSTR info = _T(" 按Enter键返回 ");
	settextstyle(20, 0, _T("黑体"));
	outtextxy(swidth / 2 - textwidth(info) / 2, 4 * sheight / 5 - textheight(info), info);

	while (true)
	{
		ExMessage mess;
		getmessage(&mess, EM_KEY);
		if (mess.vkcode == 0x0D)
		{
			return;
		}
	}
}
bool Play()
{
	setbkcolor(WHITE);
	cleardevice();
	bool be_Playing = true;
	IMAGE guardimg, enemyimg, bullet1img, bkimg, bullet2img, tipimg, tip2img;
	IMAGE edown[12];
	loadimage(&guardimg, _T("..\\..\\pic\\guard.png"), 75, 75);
	loadimage(&enemyimg, _T("..\\..\\pic\\enemy.png"), 55, 55);
	loadimage(&bullet1img, _T("..\\..\\pic\\bullet1.png"));
	loadimage(&bkimg, _T("..\\..\\pic\\bk0.png"));
	loadimage(&tipimg, _T("..\\..\\pic\\tip.png"));
	loadimage(&tip2img, _T("..\\..\\pic\\tip2.png"));
	loadimage(&bullet2img, _T("..\\..\\pic\\bullet2.png"), 8, 20);

	loadimage(&edown[0], _T("..\\..\\pic\\enemy_down\\1.png"), 55, 100);
	loadimage(&edown[1], _T("..\\..\\pic\\enemy_down\\2.png"), 55, 100);
	loadimage(&edown[2], _T("..\\..\\pic\\enemy_down\\3.png"), 55, 100);
	loadimage(&edown[3], _T("..\\..\\pic\\enemy_down\\4.png"), 55, 100);
	loadimage(&edown[4], _T("..\\..\\pic\\enemy_down\\5.png"), 55, 100);
	loadimage(&edown[5], _T("..\\..\\pic\\enemy_down\\6.png"), 55, 100);
	loadimage(&edown[6], _T("..\\..\\pic\\enemy_down\\7.png"), 55, 100);
	loadimage(&edown[7], _T("..\\..\\pic\\enemy_down\\8.png"), 55, 100);
	loadimage(&edown[8], _T("..\\..\\pic\\enemy_down\\9.png"), 55, 100);
	loadimage(&edown[9], _T("..\\..\\pic\\enemy_down\\10.png"), 55, 100);
	loadimage(&edown[10], _T("..\\..\\pic\\enemy_down\\11.png"), 55, 100);
	loadimage(&edown[11], _T("..\\..\\pic\\enemy_down\\12.png"), 55, 100);


	BK bk = BK(bkimg);
	Guard gc = Guard(guardimg);
	Tip tp = Tip(tipimg, tip);
	Tip2 tp2 = Tip2(tip2img, tip);

	vector<Enemy*>es;
	vector<Bullet1*>b1s;
	vector<Bullet2*>b2s;
	int bsing = 0;
	int ms_l_down = 0;  // 判断鼠标左键是否点击的变量
	int ms_r_down = 500;  // 判断鼠标右键是否点击的变量
	bool acc_next = false;  // 下一颗子弹是否加速的依据
	long long min = 0;
	clock_t hurtlast = clock();
	int enmu = 5;

	unsigned long long kill = 0;
	int speed = 10;
	int activity = 1;
	for (int i = 0; i < 6; i++)
	{
		AddEnemy(es, enemyimg, edown);
	}
	while (be_Playing)    // 正式游戏时不会跳出的循环
	{
		bsing++;
		if (bsing % speed == 0)
		{
			if (acc_next)
			{
				acc_next = false;
				b1s.push_back(new Bullet1(bullet1img, gc.GetRect(), true));
			}
			else {
				b1s.push_back(new Bullet1(bullet1img, gc.GetRect(), false));
			}

		}
		if (bsing == 120)
		{
			bsing = 0;
			for (auto& i : es)    // 生成敌方子弹，我方生成bsing/speed个后敌方发射一个
			{
				b2s.push_back(new Bullet2(bullet2img, i->GetRect()));
			}
		}

		// 以下为设置点击鼠标左键后，全图子弹速度的更新，加速时间为5颗子弹的生成时间内
		if (ms_l_down != 0) {
			ms_l_down--;
		}
		if (ms_l_down >= 300) {       // 这里的比较值设置加速时间
			bullet_speed = 12 + activity / 2;
			if (activity < 20)
				speed = 6 - activity / 4;
			else {
				speed = 2;
			}
		}
		else {
			if (activity < 24) {
				bullet_speed = 4 + activity / 4;
				speed = 10 - activity / 6;
			}
			else {
				speed = 5;
			}
		}

		if ((ms_l_down == 0) && (KEY_DOWN(VK_LBUTTON))) {   //判断左键
			ms_l_down = 500;          // 这里的赋值设置点击一次后不能再次点击的CD时间
		}

		// 以下为点击鼠标右键后，下一颗子弹永久弹射加速，活性增强，恢复生命值
		if (ms_r_down != 0) {
			ms_r_down--;
		}
		if ((ms_r_down == 0) && (KEY_DOWN(VK_RBUTTON))) {
			ms_r_down = 800;
			acc_next = true;
		}
		if (ms_r_down == 800) {
			gc.aid();
			activity++;
		}
		if (min <= 30001) {
			min++;
		}
		if (min % 3000 == 0) {
			miss = 0;
		}
		if (min == 1000) {
			enmu++;
		}
		if (min == 3000) {
			enmu++;
		}
		if (min == 6000) {
			enmu++;
		}
		if (min == 10000) {
			enmu++;
		}
		if (min == 15000) {
			enmu++;
		}
		if (min == 20000) {
			enmu = enmu + 2;
		}
		if (min == 25000) {
			enmu = enmu + 3;
		}
		if (min == 30000) {
			enmu = enmu + 4;
		}
		BeginBatchDraw();

		bk.Show();
		Sleep(2);
		flushmessage();
		if (ms_l_down == 0) {
			tp.Show();
		}
		if (ms_r_down == 0) {
			tp2.Show();
		}
		Sleep(2);
		gc.Control();
		if (_kbhit())
		{
			char v = _getch();
			if (v == 0x20)
			{
				Sleep(500);
				while (true)
				{
					if (_kbhit())
					{
						v = _getch();
						if (v == 0x20)
						{
							break;
						}
					}
					Sleep(16);
				}
			}
		}
		gc.Show();
		auto b1sit = b1s.begin();
		while (b1sit != b1s.end())
		{
			if (!(*b1sit)->Show())
			{
				b1sit = b1s.erase(b1sit);
			}
			else
			{
				b1sit++;
			}
		}
		auto b2sit = b2s.begin();
		while (b2sit != b2s.end())
		{
			if (!(*b2sit)->Show())
			{
				b2sit = b2s.erase(b2sit);
			}
			else
			{
				if (recttouchrect((*b2sit)->GetRect(), gc.GetRect()))
				{
					if (clock() - hurtlast >= hurttime)
					{
						be_Playing = gc.hurt();			//gc.hurt为false时跳出游戏循环，进入结算
						hurtlast = clock();
					}
				}
				b2sit++;
			}

		}
		auto it = es.begin();
		while (it != es.end())
		{
			if (recttouchrect((*it)->GetRect(), gc.GetRect()))
			{
				if (clock() - hurtlast >= hurttime)
				{
					be_Playing = gc.hurt();
					hurtlast = clock();
				}
			}
			auto b1it = b1s.begin();
			while (b1it != b1s.end())
			{
				if (recttouchrect((*b1it)->GetRect(), (*it)->GetRect()))
				{
					(*it)->Isdie();
					delete(*b1it);
					b1s.erase(b1it);

					kill++;
					break;
				}
				b1it++;
			}
			if (!(*it)->Show())
			{
				delete(*it);
				es.erase(it);
				it = es.begin();
			}
			it++;
		}
		if (miss == 10) {
			be_Playing = false;
		}
		for (int i = 0; i < enmu - es.size(); i++)
		{
			AddEnemy(es, enemyimg, edown);
		}
		EndBatchDraw();    // 批量绘图，在此之后做一次全图刷新

	}
	if (miss == 10) {
		ms_r_down = 0;
		ms_l_down = 0;
		activity = 1;
		min = 0;
		enmu = 0;
		bsing = 0;
		Miss(kill);
	}
	else {
		ms_r_down = 0;
		ms_l_down = 0;
		activity = 1;
		min = 0;
		enmu = 0;
		bsing = 0;
		Over(kill);
	}
	return(true);
}

int main()
{
	initgraph(swidth, sheight, EW_NOMINIMIZE | EW_SHOWCONSOLE);
	bool is_alive = true;
	while (is_alive)
	{
		Welcome();

		is_alive = Play();
	}

	return 0;
}